package cc.c3p0.admin.common.aspect;

import cc.c3p0.admin.common.constants.SystemConstants;
import cc.c3p0.admin.module.syslog.service.SyslogSercieI;
import cc.c3p0.admin.mybatis.model.AdminSyslog;
import cc.c3p0.admin.mybatis.model.AdminUser;
import com.alibaba.druid.support.json.JSONUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * 系统日志AOP
 * Created by binchao on 2017/4/17.
 */
@Aspect
@Component
public class SystemLogAspect  {

    private static final Logger LOG = LoggerFactory.getLogger(SystemLogAspect.class);

    @Resource
    private SyslogSercieI syslogSercie;

    /**
     * 日志
     */
    private AdminSyslog log;

    /**
     * action处理开始时间
     */
    private Date startTime;

    /**
     * action处理结束时间
     */
    private Date endTime;

    /**
     * 业务处理开始时间
     */
    private Date serviceStartTime;

    /**
     * 业务处理结束时间
     */
    private Date serviceEndTime;


    /**
     * controller point cut
     */
    @Pointcut("execution(* cc.c3p0.*.controller.*(..)) || @annotation(cc.c3p0.admin.common.annotation.SystemControllerLog)")
    private void controllerAspect() {}

    /**
     * service point cut
     */
    @Pointcut("execution(* cc.c3p0.*.module.*.service.impl.*(..)) || @annotation(cc.c3p0.admin.common.annotation.SystemServiceLog)")
    private void serviceAspect() {}

    @Before("controllerAspect()")
    public void doControllerBefore(JoinPoint joinPoint) {
        startTime = new Date();
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder
                .getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        AdminUser user = (AdminUser) session.getAttribute(SystemConstants.USER);

        String host = request.getRemoteAddr();
        try {
            LOG.info("=====前置通知开始=====");
            LOG.info("请求方法：" + (joinPoint.getTarget().getClass().getName())
                    + "." + joinPoint.getSignature().getName() + "()");
            LOG.info("请求用户：" + (null == user ? "匿名" : user.getUsername()));
            LOG.info("请求IP：" + host);

            log = new AdminSyslog();
            log.setActionStartTime(startTime);
            log.setHost(host);
            log.setUserid(null == user ? null : user.getId());
            log.setRequestpath(request.getRequestURI());
            log.setMethod(joinPoint.getTarget().getClass().getName() + "."
                    + joinPoint.getSignature().getName() + "()");
        } catch (Exception e) {
            LOG.error("=====前置通知异常=====");
            LOG.error("异常信息：{}", e.getMessage());
        }
    }

    @After("controllerAspect()")
    public void doControllerAfter(JoinPoint joinPoint) {
        endTime = new Date();
        long totalTime = endTime.getTime() - startTime.getTime();

        log.setActionEndTime(endTime);

        /**
         * 业务处理耗时计算
         */
        if (null != serviceStartTime && null != serviceEndTime) {
            long serviceTotalTime = serviceEndTime.getTime() - serviceStartTime.getTime();
            log.setActionTotalTime(totalTime - serviceTotalTime);
            log.setServiceStartTime(serviceStartTime);
            log.setServiceEndTime(serviceEndTime);
            log.setServiceTotalTime(serviceTotalTime);
        }

        log.setTotalTime(totalTime);
        log.setType("0");
        log.setCreatetime(new Date());
        syslogSercie.save(log);
    }

    @Before("serviceAspect()")
    public void doServiceBefore(JoinPoint joinPoint) {
        serviceStartTime = new Date();
    }

    @After("serviceAspect()")
    public void doServiceAfter(JoinPoint joinPoint) {
        serviceEndTime = new Date();
    }

    @AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder
                .getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        AdminUser user = (AdminUser) session.getAttribute(SystemConstants.USER);
        String host = request.getRemoteAddr();
        StringBuilder params = new StringBuilder();
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
                params.append(JSONUtils.toJSONString(joinPoint.getArgs()[i])).append(";");
            }
        }
        try {
            LOG.error("=====异常通知开始=====");
            LOG.error("异常代码：{}", e.getClass().getName());
            LOG.error("异常信息：{}", e.getMessage());
            LOG.error("异常方法：{}", (joinPoint.getTarget().getClass().getName() +
                "." + joinPoint.getSignature().getName() + "()"));
            LOG.error("请求人：{}", user.getUsername());
            LOG.error("IP：{}", host);
            LOG.error("请求参数：{}", params);
            log.setType("1");
            log.setCreatetime(new Date());
            syslogSercie.save(log);
        } catch (Exception e1) {
            LOG.error("记录日志出错：{}", e1.getMessage());
        }
    }
}
